package com.black.gateway.permission.service.impl;

import com.black.gateway.feign.PlatformServiceApi;
import com.black.gateway.permission.service.PermissionHandlerService;
import com.black.gateway.web.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author linwenfeng
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PermissionHandlerServiceImpl implements PermissionHandlerService {


    private static final ConcurrentHashMap<String, Set<Long>> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();

    private static volatile Set<String> PERMISSION_PATH_SET = new HashSet<>();

    private static volatile Set<String> WHITE_PATH_SET = new HashSet<>();

    private static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(1, r -> {
        Thread thread = new Thread(r);
        thread.setName("PermissionHandlerService_Thread");
        return thread;
    });

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    private final PlatformServiceApi platformServiceApi;

    @PostConstruct
    private void init() {
        this.initAllRouterPermissionsData(30);
        this.initAllWhitePath(30);
    }

    @Override
    public boolean isWhitePath(String path) {
        return WHITE_PATH_SET.stream().anyMatch(item -> pathMatcher.match(item, path));
    }

    @Override
    public boolean isRefreshPermissionPath(String path) {
        return pathMatcher.match("/refreshRouterPermission", path);
    }

    @Override
    public boolean isRefreshWithPath(String path) {
        return pathMatcher.match("/refreshWhitePath", path);
    }

    @Override
    public String getPermissionPath(String path) {
        Optional<String> permissionPath = PERMISSION_PATH_SET.stream().filter(item -> pathMatcher.match(item, path)).findAny();
        return permissionPath.orElse(null);
    }

    @Override
    public boolean isHavePermission(String permissionPath, Long userId) {
        Set<Long> pathHavingRoleIdSet = CONCURRENT_HASH_MAP.get(permissionPath);
        if (CollectionUtils.isEmpty(pathHavingRoleIdSet)) {
            return false;
        }
        ApiResponse<Set<Long>> apiResult = platformServiceApi.getShareUserHavingRoleIdByUserId(userId);
        if (apiResult != null && apiResult.success()) {
            Set<Long> result = apiResult.getResult();
            HashSet<Long> resSet = new HashSet<>(pathHavingRoleIdSet);
            resSet.retainAll(result);
            return resSet.size() > 0;
        }
        return false;
    }

    @Override
    public void initAllRouterPermissionsData(int seconds) {
        EXECUTOR.schedule(() -> {
            try {
                log.info("initAllRouterPermissionsData--------->开始");
                ApiResponse<Map<String, Set<Long>>> apiResult = platformServiceApi.getAllRouterPermissions();
                if (apiResult != null && apiResult.success()) {
                    Map<String, Set<Long>> result = apiResult.getResult();
                    PERMISSION_PATH_SET = result.keySet();
                    for (Map.Entry<String, Set<Long>> entry : result.entrySet()) {
                        CONCURRENT_HASH_MAP.put(entry.getKey(), entry.getValue());
                    }
                }
                log.info("initAllRouterPermissionsData--------->结束");
            } catch (Exception exception) {
                log.error("initAllRouterPermissionsData------>出错", exception);
                initAllRouterPermissionsData(seconds);
            }
        }, seconds, TimeUnit.SECONDS);
    }

    @Override
    public void initAllWhitePath(int seconds) {
        EXECUTOR.schedule(() -> {
            try {
                log.info("initAllWhitePath--------->开始");
                ApiResponse<Set<String>> apiResult = platformServiceApi.getAllWhitePath();
                if (apiResult != null && apiResult.success()) {
                    WHITE_PATH_SET = apiResult.getResult();
                }
            } catch (Exception exception) {
                log.error("initAllWhitePath------>出错", exception);
                initAllWhitePath(seconds);
            }
        }, seconds, TimeUnit.SECONDS);
    }
}
